#pragma once 

#ifndef __CORE_rtti_H__
#define __CORE_rtti_H__

#include "FLOW_core/namespace.h"
#include "FLOW_core/core_types.h"

//Uncomment this to have the method GetClassName( ) enabled in the CRTTI class
#define CLASSNAME_QUERY_ENABLED

namespace CORE
{
	template< typename ClassType >
	struct TypeInfo
	{
		typedef ClassType type;
	};

	//! Class to make possible dynamic cast efficiently
	class CRTTI
	{
	private:
#if defined( CLASSNAME_QUERY_ENABLED )
		const char_t* const m_psz_class_name;
#endif
		const CRTTI* const m_p_parent_rtti;

	public:
		//!Default constructor
		CRTTI( const char_t* apsz_class_name, const CRTTI* ap_parent_rtti ) :
#if defined( CLASSNAME_QUERY_ENABLED )
			m_psz_class_name( apsz_class_name ),
#endif
			m_p_parent_rtti( ap_parent_rtti )
		{
		}

		//!Destructor
		~CRTTI( ) {}

		//! Returns class name
#if defined( CLASSNAME_QUERY_ENABLED )
		inline const char* GetClassName( void ) const
		{
			return m_psz_class_name;
		}
#endif

		//! Returns the parent RTTI
		inline const CORE::CRTTI* GetParentRTTI( void ) const
		{
			return m_p_parent_rtti;
		}

	}; //CRTTI class
} 

//! WARNING this macro must be used inside a class declaration, it leaves the declaration in private: state
//! the ClassName must be the name of the class we are calling the macro inside
#define DECLARE_RTTI_CLASS( ClassName, ParentClassName )												\
	public:																								\
		template< typename DerivedType >																\
		DerivedType* DynamicCast( void )																\
		{																								\
			const CORE::CRTTI* p_rtti = NULL;															\
			for( p_rtti = DerivedType::GetClassRTTI( );													\
				 p_rtti && p_rtti != &s_rtti;															\
				 p_rtti = p_rtti->GetParentRTTI( ) );													\
			return ( p_rtti ) ? reinterpret_cast< DerivedType* >( this ) : NULL;						\
		}																								\
		template< typename DerivedType >																\
		const DerivedType* DynamicCast( void ) const													\
		{																								\
			const CORE::CRTTI* p_rtti = NULL;															\
			for( p_rtti = DerivedType::GetClassRTTI( );													\
				 p_rtti && p_rtti != &s_rtti;															\
				 p_rtti = p_rtti->GetParentRTTI( ) );													\
			return ( p_rtti ) ? reinterpret_cast< DerivedType* >( this ) : NULL;						\
		}																								\
		virtual const CORE::CRTTI* GetRTTI( void ) const												\
		{																								\
			return &s_rtti;																				\
		}																								\
		inline static const CORE::CRTTI* GetClassRTTI( void )											\
		{																								\
			return &s_rtti;																				\
		}																								\
	private:																							\
		static const CORE::CRTTI s_rtti;									

#define DECLARE_RTTI_ROOT_CLASS( ClassName )	DECLARE_RTTI_CLASS( ClassName, NULL )

// Use this macro in the definition of each RTTI class
#define DEFINE_RTTI_CLASS( ClassName, ParentClassName ) const CORE::CRTTI ClassName::s_rtti( #ClassName, ParentClassName::GetClassRTTI( ) )

#define DEFINE_RTTI_ROOT_CLASS( ClassName ) const CORE::CRTTI ClassName::s_rtti( #ClassName, NULL )

#endif
